/**
 * 
 */
package pl.com.qapps.datastore.berkeley.impl;

import java.io.IOException;
import java.util.List;

import pl.com.qapps.datastore.EntityStore;

import com.google.appengine.api.datastore.Entity;
import com.google.appengine.api.datastore.EntityTranslator;
import com.google.appengine.api.datastore.Key;
import com.google.appengine.api.datastore.Transaction;
import com.google.storage.onestore.v3.OnestoreEntity.EntityProto;
import com.sleepycat.je.Database;
import com.sleepycat.je.DatabaseConfig;
import com.sleepycat.je.DatabaseEntry;
import com.sleepycat.je.Environment;
import com.sleepycat.je.LockMode;
import com.sleepycat.je.OperationStatus;

/**
 * @author Jakub Dykowski
 * 
 */
public class BerkeleyEntityStore extends StoreTable implements EntityStore {

	private final Database db;

	public BerkeleyEntityStore(Environment env, String filename) {
		super(env);

		DatabaseConfig cfg = new DatabaseConfig();
		cfg.setTransactional(true);
		cfg.setAllowCreate(true);
		cfg.setSortedDuplicates(false);
		// entityCfg.setBtreeComparator(COMPARATOR);

		db = env.openDatabase(null, filename, cfg);

	}

	Database getDatabase() {
		return db;
	}

	@Override
	public void close() throws IOException {
		db.close();
	}

	@Override
	public Entity get(Key key, Transaction txn) {

		DatabaseEntry keyData = new DatabaseEntry();
		EntityBindings.ENTITY_KEY_BINDING.objectToEntry(key, keyData);

		DatabaseEntry entityData = new DatabaseEntry();
		OperationStatus status = db.get(toInternal(txn), keyData, entityData,
				LockMode.READ_COMMITTED);
		if (status == OperationStatus.SUCCESS) {
			EntityProto proto = EntityBindings.ENTITY_BINDING.entryToObject(
					keyData, entityData);
			return EntityTranslator.createFromPb(proto);
		} else
			return null;
	}

	@Override
	public void put(Entity entity, Transaction txn) throws IOException {
		DatabaseEntry keyData = new DatabaseEntry();
		DatabaseEntry entityData = new DatabaseEntry();

		EntityProto proto = EntityTranslator.convertToPb(entity);

		EntityBindings.ENTITY_BINDING.objectToData(proto, entityData);
		EntityBindings.ENTITY_BINDING.objectToKey(proto, keyData);

		// keyData.setData(BytesHelper.serialize(entity.getKey()));
		// entityData.setData(EntityTranslator.convertToPb(entity).toByteArray());

		OperationStatus result = db.put(toInternal(txn), keyData, entityData);
		if (result != OperationStatus.SUCCESS)
			throw new IOException("operation failed");
	}

	@Override
	public void delete(Key key, Transaction txn) throws IOException {
		DatabaseEntry keyData = new DatabaseEntry();
		EntityBindings.ENTITY_KEY_BINDING.objectToEntry(key, keyData);

		OperationStatus status = db.delete(toInternal(txn), keyData);
		if (status != OperationStatus.SUCCESS)
			throw new IOException("operation failed");
	}

	private static com.sleepycat.je.Transaction toInternal(Transaction txn) {
		return txn != null ? ((BerkeleyTransaction) txn).raw : null;
	}

}
